CloudFormation一撃でGuardDutyを有効にして、通知をLambdaでイイ感じに編集してSNSへ通知するテンプレート作った
GuardDutyまじ優秀を定期的につぶやいているAWS事業本部 梶原@新福岡オフィスです。
完全に 「一発でGuardDutyを全リージョン有効化して通知設定するテンプレート作った」
とほぼ内容被ってますが、リージョンごとにSNSを作りたくない。リージョンをまたぐ際の呼び出しコストなどは認識しているけど、まぁ、大丈夫という構成の場合に使用してください。
構成はこんな感じです。
AWS構成図
CloudFormationテンプレートの実行
1つのリージョンだけで、GuardDutyを有効にする場合はSNSのトピックを作成して、下記テンプレートを実行してください。 さくっとGuardDutyを有効にまた通知を作成できるかと思います。
テンプレートはS3に置いてますので、ログイン後に以下ボタンをポチっとしてください。
※IAMの権限(AWS Lambda用のIAM Roleを作成します)の確認がありますので、AWS CloudFormation によって IAM リソースが作成される場合があることを承認します。
にチェックをして進めてください。
パラメータ
- EnableGuardDutyDetector: は実行するリージョンで有効にする場合はtrueを選択して下さい(すでに有効にしている場合はfalse)
- MinSeverity: 通知するSeverityを指定します(デフォルトでは5以上を指定していますがすべて通知する場合は0を選択)
- SnsTopicArn: 通知先のSNSのARNを指定してください。
※複数のリージョンで構成する場合は、Stacksetsを作成して、各リージョンにテンプレートを展開、リソースを作成してください。
StackSetsの作成方法などは
をご参考ください
S3ののテンプレートURLは https://pub-devio-blog-vtuisp2o.s3.amazonaws.com/template/guardduty-sns-withroll.yml になります
SNS通知
脅威を検知した場合、SNSへ通知が送られます。 通知内容は下記のような通知になります(サンプルです)
Subject:[GuardDuty Finding] EC2 instance i-99999999 is communicating with a Drop Point.
GuardDuty Finding ------------------------------ schemaVersion: 2.0 accountId: XXXXXXXXXXXX region: ap-southeast-2 partition: aws id: 9ab66955e7b313cf77fbdbe7d164cc13 arn: arn:aws:guardduty:ap-southeast-2:XXXXXXXXXXXX:detector/c0b66941518c08d9fe004f6de4168aeb/finding/9ab66955e7b313cf77fbdbe7d164cc13 type: Trojan:EC2/DropPoint severity: 5 createdAt: 2019-08-27T10:42:50.854Z updatedAt: 2019-08-27T10:42:50.854Z title: EC2 instance i-99999999 is communicating with a Drop Point. description: EC2 instance i-99999999 is communicating with a remote host 198.51.100.0 that is known to hold credentials and other stolen data captured by malware. ------------------------------ For details, please refer to the following URL:https://ap-southeast-2.console.aws.amazon.com/guardduty/home?region=ap-southeast-2#/findings?fId=9ab66955e7b313cf77fbdbe7d164cc13 ------------------------------
というような内容で通知されますので、文中のURLのリンクに飛ぶと、GuardDutyのコンソールで該当の脅威を表示するようにしています。 (こちらは現時点のコンソールのリンクとなりますので、今後も動作するかどうは未定です。Lambda中で編集をおこなってますので、適時Lambdaを修正してください)
テンプレート
テンプレートを置いておきますので、ご自由にご編集ください。
AWSTemplateFormatVersion: 2010-09-09 Description: "enable guardduty and create SnsPublishLambda" Parameters: EnableGuardDutyDetector: Type: String Default: no AllowedValues: [yes, no] SnsTopicArn: Description: Enter SNS Topic Arn Type: String MinSeverity: Description: Enter Min publish Severity Type: Number Default: 5 Conditions: EnableGuardDutyDetector: !Equals [ !Ref EnableGuardDutyDetector, yes ] Resources: GuardDutyDetector: Condition: EnableGuardDutyDetector Type: "AWS::GuardDuty::Detector" Properties: Enable: true GuardDutyFindingsEventsRule: Type: "AWS::Events::Rule" Properties: Name: GuardDutyFindingsEventsRule Description: "Alert to Lambda when find threats by GuardDuty" EventPattern: source: - aws.guardduty detail-type: - GuardDuty Finding Targets: - Id: GuardDutyFindingsTargets1 Arn: !GetAtt SnsPublishFunction.Arn SnsPublishFunction: Type: AWS::Lambda::Function Properties: Handler: index.handler Role: !GetAtt LambdaExecutionRole.Arn Environment: Variables: SNS_TOPIC_ARN: !Ref SnsTopicArn MIN_SEVERTIY: !Ref MinSeverity Code: ZipFile: !Sub | var SNS_TOPIC_ARN = process.env.SNS_TOPIC_ARN; var MIN_SEVERTIY = process.env.MIN_SEVERTIY; var AWS = require('aws-sdk'); exports.handler = async(event) => { var severity = event.detail.severity; if(severity < MIN_SEVERTIY) { return; } var message = `${!event["detail-type"]}\n`; message += "------------------------------\n"; for (const key in event.detail) { if (typeof(event.detail[key]) != 'object') message += `${!key}: ${!event.detail[key]}\n`; } message += "------------------------------\n"; var url = `https://${!event.region}.console.aws.amazon.com/guardduty/home?region=${!event.region}#/findings?fId=${!event.detail.id}`; message += `For details, please refer to the following URL:${!url}\n`; message += "------------------------------\n"; var subject = `[${!event["detail-type"]}] ${!event.detail.title}`; subject = subject.replace(/[\u{0080}-\u{FFFF}]/gu,"") // remove not ASCII .replace(/\r?\n/g, "") // remove return .slice(0, 100); // SNS Publish var params = { Message: message, Subject: subject, TopicArn: SNS_TOPIC_ARN }; var SNS_REGION = SNS_TOPIC_ARN.split(":")[3]; var sns = new AWS.SNS({region: SNS_REGION}); var result = await sns.publish(params).promise(); return result; } Runtime: nodejs12.x Timeout: 30 LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Path: "/" Policies: - PolicyName: LambdaExecutionRole-SnsPublishPolicy PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - sns:Publish Resource: !Ref SnsTopicArn LambdaInvokePermission: Type: AWS::Lambda::Permission Properties: FunctionName: !GetAtt SnsPublishFunction.Arn Action: lambda:InvokeFunction Principal: events.amazonaws.com SourceArn: !GetAtt GuardDutyFindingsEventsRule.Arn
まとめ
先行する小ネタ2つに引っかかりましたが、GuardDuty有効にしたいけど、SNSのトピックあまりつくりたくないんだよねーという要望にはまると幸いです。 Lambda部分などは最適化余地がたくさんあるかとおもうんで、ぜひいい感じの通知内容ができたら教えてください。 StacksSetsの部分はカスタムリソースなどをつくってホントの一撃をしたいなと思ったんですが、要望があればがんばりますので、応援してください。
参考URL
一発でGuardDutyを全リージョン有効化して通知設定するテンプレート作った
[新機能] CloudFormation StackSetsを試してみた